/**
 * 
 */
package com.ld.tamp.web.service;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;

import com.ld.base.helper.DateUtils;
import com.ld.base.support.PropertyHolder;
import com.ld.net.wxb.WeixBasicDataRequest.D_funcl_wxb_addWxConfig_Request;
import com.ld.net.wxb.WeixBasicDataRequest.D_funcl_wxb_delWxConfig_Request;
import com.ld.net.wxb.WeixBasicDataRequest.D_funcl_wxb_modiWxConfig_Request;
import com.ld.net.wxb.WeixBasicDataRequest.D_funcl_wxb_queryWxConfig_Request;
import com.ld.net.wxb.WeixBasicDataResponse.D_funcl_wxb_queryWxConfig_Response;
import com.ld.net.wxb.service.IWeixBasicService;
import com.ld.tamp.web.constant.WeiXinConstant;
import com.ld.tamp.web.dao.AuthorizerInfoDao;
import com.ld.tamp.web.dao.AuthorizerJsTicketDao;
import com.ld.tamp.web.dao.ComponentAccessTokenDao;
import com.ld.tamp.web.dao.ComponentVerifyTicketDao;
import com.ld.tamp.web.event.AuthorizationEvent;
import com.ld.tamp.web.event.ReceiveComponentVerifyTicketEvent;
import com.ld.tamp.web.event.UnAuthorizationEvent;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;

import weixin.popular.api.ComponentAPI;
import weixin.popular.api.TicketAPI;
import weixin.popular.bean.component.ApiGetAuthorizerInfoResult;
import weixin.popular.bean.component.ApiGetAuthorizerInfoResult.Authorizer_info;
import weixin.popular.bean.component.ApiQueryAuthResult;
import weixin.popular.bean.component.ApiQueryAuthResult.Authorization_info;
import weixin.popular.bean.component.ComponentReceiveXML;
import weixin.popular.bean.component.PreAuthCode;
import weixin.popular.bean.ticket.Ticket;
import weixin.popular.util.StreamUtils;
import weixin.popular.util.XMLConverUtil;

/**
 * 
 * 授权服务
 * @author KeYang
 *
 */
@Service
public class AuthorizationService implements ApplicationEventPublisherAware{
	
	private static final Logger logger = LoggerFactory.getLogger(AuthorizationService.class);
	
	
	@Autowired
	IWeixBasicService wxservice;
	
	@Autowired
    private ComponentVerifyTicketDao componentVerifyTicketDao;
	
	@Autowired
    private ComponentAccessTokenDao componentAccessTokenDao;
	
	@Autowired
	private AuthorizerInfoDao authorizerInfoDao;
	
	@Autowired
	private AuthorizerJsTicketDao authorizerJsTicketDao;
	
    private ApplicationEventPublisher publisher;
    
	/**
	 * 授权事件
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	public void processAuthorizeEvent(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ServletInputStream inputStream = request.getInputStream();
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String msgSignature = request.getParameter("msg_signature");
		String componentToken = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_TOKEN);
		String componentAppid = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_APPID);
		String componentEncodingAesKey = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_ENCODING_AES_KEY);

		WXBizMsgCrypt wxBizMsgCrypt = null;
		ComponentReceiveXML componentReceiveXml = null;

		boolean isEncrypt = StringUtils.isNotEmpty(msgSignature);

		String authorizerAppid,authCode,componentAccessToken;

		if (isEncrypt) {
			try {
				wxBizMsgCrypt = new WXBizMsgCrypt(componentToken, componentEncodingAesKey, componentAppid);
				String postData = StreamUtils.copyToString(inputStream, Charset.forName("utf-8"));
				String xmlData = wxBizMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, postData);
				componentReceiveXml = XMLConverUtil.convertToObject(ComponentReceiveXML.class, xmlData);
			} catch (AesException e) {
				e.printStackTrace();
			}
		}
		if (componentReceiveXml != null) {
			switch (componentReceiveXml.getInfoType()) {
			case "component_verify_ticket":
				String componentVerifyTicket = componentReceiveXml.getComponentVerifyTicket();
				if (StringUtils.isNotEmpty(componentVerifyTicket)) {
					logger.info("-推送component_verify_ticket协议---ticket:{},time:{}---", componentVerifyTicket, DateUtils.date2String(new Date(), "yyyyMMdd HH:mm:ss"));
					componentVerifyTicketDao.save(componentVerifyTicket);
					ReceiveComponentVerifyTicketEvent receiveComponentVerifyTicketEvent = new ReceiveComponentVerifyTicketEvent(
							this, componentVerifyTicket);
					publisher.publishEvent(receiveComponentVerifyTicketEvent);
				}
				return;
			case "unauthorized":
				authorizerAppid = componentReceiveXml.getAuthorizerAppid();
				logger.info("-公众号取消授权,appid:{},time:{}---", authorizerAppid, DateUtils.date2String(new Date(), "yyyyMMdd HH:mm:ss"));
				this.deleteAuthInfo(authorizerAppid);
				break;
			case "updateauthorized":case"authorized":
				authorizerAppid = componentReceiveXml.getAuthorizerAppid();
				logger.info("-公众号授权/更新授权,appid:{},time:{}---", authorizerAppid, DateUtils.date2String(new Date(), "yyyyMMdd HH:mm:ss"));
				authCode = request.getParameter("auth_code");
				componentAccessToken = componentAccessTokenDao.read().getComponentAccessToken();
				ApiQueryAuthResult queryAuthResult = ComponentAPI.api_query_auth(componentAccessToken, componentAppid, authCode);
				if (queryAuthResult.isSuccess()) {
					Authorization_info authorizationInfo = queryAuthResult.getAuthorization_info();
					this.updateAuthInfo(authorizationInfo);
				}
				return;
			default:
				return;
			}
		}
	}

	/**
	 * 
	 */
	public void deleteAuthInfo(String authorizerAppid) {
		D_funcl_wxb_delWxConfig_Request delWxConfigRequest = new D_funcl_wxb_delWxConfig_Request();
		
		delWxConfigRequest.setApp_id(authorizerAppid);
		wxservice.funcl_wxb_delWxConfig(delWxConfigRequest);
		UnAuthorizationEvent unAuthorizationEvent = new UnAuthorizationEvent(this,authorizerAppid);
		publisher.publishEvent(unAuthorizationEvent);
	}

	/**
	 * 更新授权公众号信息
	 * @param authorizationInfo
	 */
	private void updateAuthInfo(Authorization_info authorizationInfo) {
		
		Authorizer_info authorizerInfo;
		D_funcl_wxb_queryWxConfig_Response queryWxConfigResponse;
		List<D_funcl_wxb_queryWxConfig_Response> queryWxConfigResponseList;
		D_funcl_wxb_queryWxConfig_Request queryWxConfigRequest = new D_funcl_wxb_queryWxConfig_Request();
		D_funcl_wxb_modiWxConfig_Request modifyWxConfigRequest = new D_funcl_wxb_modiWxConfig_Request();
		String componentAccessToken = componentAccessTokenDao.read().getComponentAccessToken();
		String componentAppid = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_APPID);
		String authorizerAppid = authorizationInfo.getAuthorizer_appid();
		//获取授权方的账户信息
		ApiGetAuthorizerInfoResult apiGetAuthorizerInfoResult = ComponentAPI.api_get_authorizer_info(componentAccessToken, componentAppid, authorizerAppid);
		if(apiGetAuthorizerInfoResult.isSuccess()){
			authorizerInfo = apiGetAuthorizerInfoResult.getAuthorizer_info();
			queryWxConfigRequest.setApp_id(authorizationInfo.getAuthorizer_appid());
			queryWxConfigResponseList =  wxservice.funcl_wxb_queryWxConfig(queryWxConfigRequest);
			if(CollectionUtils.isNotEmpty(queryWxConfigResponseList)){
				queryWxConfigResponse = queryWxConfigResponseList.get(0);
				modifyWxConfigRequest.setCo_no(queryWxConfigResponse.getCo_no());
				modifyWxConfigRequest.setApp_id(queryWxConfigResponse.getApp_id());
				modifyWxConfigRequest.setApp_img(authorizerInfo.getHead_img());
				modifyWxConfigRequest.setApp_name(authorizerInfo.getPrincipal_name());
				modifyWxConfigRequest.setApp_url(authorizerInfo.getQrcode_url());
				modifyWxConfigRequest.setService_type(Integer.toString(authorizerInfo.getService_type_info().getId()));
				modifyWxConfigRequest.setVerify_type(Integer.toString(authorizerInfo.getVerify_type_info().getId()));
				wxservice.funcl_wxb_modiWxConfig(modifyWxConfigRequest);
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
	 */
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
			this.publisher = applicationEventPublisher;
	}

	/**
	 * 授权回调函数
	 * 新增授权信息
	 * @param companyNo
	 * @param request
	 * @param response
	 */
	public void saveAuthInfo(Long companyNo, String authCode) {
		Authorizer_info authorizerInfo;
		Authorization_info authorizationInfo;
		AuthorizationEvent authorizationEvent;
		D_funcl_wxb_queryWxConfig_Request queryWxConfigRequest = new D_funcl_wxb_queryWxConfig_Request();
		List<D_funcl_wxb_queryWxConfig_Response> queryWxConfigResponse = null;
		D_funcl_wxb_addWxConfig_Request addWxConfigRequest = new D_funcl_wxb_addWxConfig_Request();
		D_funcl_wxb_modiWxConfig_Request modifyWxConfigRequest = new D_funcl_wxb_modiWxConfig_Request();
		
		String componentAccessToken = componentAccessTokenDao.read().getComponentAccessToken();
		String componentAppid = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_APPID);
		ApiQueryAuthResult queryAuthResult = ComponentAPI.api_query_auth(componentAccessToken, componentAppid, authCode);
		if (queryAuthResult.isSuccess()) {
			authorizationInfo = queryAuthResult.getAuthorization_info();
			ApiGetAuthorizerInfoResult apiGetAuthorizerInfoResult = ComponentAPI.api_get_authorizer_info(componentAccessToken, componentAppid, authorizationInfo.getAuthorizer_appid());
			authorizerInfo = apiGetAuthorizerInfoResult.getAuthorizer_info();
			//基本信息更新入库 
			queryWxConfigRequest.setCo_no(companyNo);
			queryWxConfigRequest.setApp_id(authorizationInfo.getAuthorizer_appid());
			queryWxConfigRequest.setRow_count(-1L);
			try{
				queryWxConfigResponse = wxservice.funcl_wxb_queryWxConfig(queryWxConfigRequest);
				if(CollectionUtils.isNotEmpty(queryWxConfigResponse)){
					modifyWxConfigRequest.setCo_no(Long.valueOf(companyNo));
					modifyWxConfigRequest.setApp_id(authorizationInfo.getAuthorizer_appid());
					modifyWxConfigRequest.setApp_img(authorizerInfo.getHead_img());
					modifyWxConfigRequest.setApp_name(authorizerInfo.getPrincipal_name());
					modifyWxConfigRequest.setApp_url(authorizerInfo.getQrcode_url());
					modifyWxConfigRequest.setService_type(Integer.toString(authorizerInfo.getService_type_info().getId()));
					modifyWxConfigRequest.setVerify_type(Integer.toString(authorizerInfo.getVerify_type_info().getId()));
					wxservice.funcl_wxb_modiWxConfig(modifyWxConfigRequest);
				}else{
					addWxConfigRequest.setCo_no(Long.valueOf(companyNo));
					addWxConfigRequest.setApp_id(authorizationInfo.getAuthorizer_appid());
					addWxConfigRequest.setApp_img(authorizerInfo.getHead_img());
					addWxConfigRequest.setApp_name(authorizerInfo.getPrincipal_name());
					addWxConfigRequest.setApp_url(authorizerInfo.getQrcode_url());
					addWxConfigRequest.setService_type(Integer.toString(authorizerInfo.getService_type_info().getId()));
					addWxConfigRequest.setVerify_type(Integer.toString(authorizerInfo.getVerify_type_info().getId()));
					wxservice.funcl_wxb_addWxConfig(addWxConfigRequest);
				}
			}catch(Exception e){
				logger.error("查询微信配置失败，机构编号：{}",companyNo,e);
			}
			//token入缓存
			authorizerInfoDao.save(authorizationInfo);
			Ticket ticket = TicketAPI.ticketGetticket(authorizationInfo.getAuthorizer_access_token());
			authorizerJsTicketDao.update(authorizationInfo.getAuthorizer_appid(), ticket);
			authorizationEvent = new AuthorizationEvent(this,authorizationInfo);
			publisher.publishEvent(authorizationEvent);
		}else{
			logger.error("查询授权信息失败,auth_code:{},result:{}",authCode,queryAuthResult.getErrmsg());
		}
	}
	
	/**
	 * 
	 * @param host 域名
	 * @param companyNo 机构编号
	 * @return
	 */
	public String generateAuthUrl(String redirectUrl) {
		
		String componentAppid = PropertyHolder.getProperty(WeiXinConstant.COMPONENT_APPID);
		
		String componentAccessToken = componentAccessTokenDao.read().getComponentAccessToken();
		PreAuthCode preAuthCode = ComponentAPI.api_create_preauthcode(componentAccessToken, componentAppid);
		if (preAuthCode.isSuccess()) {
			return ComponentAPI.componentloginpage(componentAppid, preAuthCode.getPre_auth_code(), redirectUrl);
		}
		return "";
	}
	
}

